﻿/// NOTES
/// todo: select how to sync (currently implicit to destination)
///       other ways to convert tabs from edge journal? 
/// todo: check subfolders
/// todo: partnership overview: add / remove / change / specific behaviour (only overwrite, create new notebook etc.)

/// TODO: create watchers to identify changes in the structure
/// link: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/54b90797-22ea-4c85-90ce-952700415aea
/// note: create and destroy with folder list in importerpreferences & at start up / destruction time
/// TODO!!!: this could work for onenote too!

/// relevant links
/// xournal xml structure (used by the Edge): http://xournal.sourceforge.net/manual.html
/// OneNote xml, API: http://msdn.microsoft.com/en-us/library/ms788684(v=office.12).aspx
/// ONENOTE 2010: http://msdn.microsoft.com/en-us/library/gg649853.aspx

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Xml.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Management;
using OneNote = Microsoft.Office.Interop.OneNote;

using System.Windows.Ink;
using System.Windows.Input;
using System.Runtime.InteropServices;

namespace ESJImporter
{
    public partial class ESJImporterForm : Form
    {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetForegroundWindow(IntPtr hWnd);

        private ListViewColumnSorter lvwColumnSorter;

        OneNote.Application onenoteApp;         // a reference to the onenote application
        ESJournal EdgeJournal;                  // the edge journal
        ImporterPreferences dlg_preferences;    // the preferences dialog 
        //ArrayList list_selectedfolders;       // list of folders to look for edge journal files
        string conffile;
        string logfile;
        //ArrayList array_Partnerships;           // big TODO: list existing partnerships
        SyncProgress dlg_progress;              // the progress bar for syncing
        public Preferences pref_Settings;       // the preferences for this instance
        ArrayList list_DirectoryWatchers;       // a set of watchers for the specified folders

        /// <summary>
        /// init
        /// </summary>
        public ESJImporterForm()
        {
            InitializeComponent();
            pref_Settings = new Preferences();

            conffile = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\esjconfig.xml";
            logfile = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\edgesync.log";
            try
            {
                File.CreateText(logfile);
            }
            catch (Exception ex)
            {
                MessageBox.Show("It seems there was a problem creating / opening the log file. No log will be created." + System.Environment.NewLine + "Detailed error message:" + System.Environment.NewLine + ex.Message, "Log File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                logfile = "";
            }

            lvwColumnSorter = new ListViewColumnSorter();
            listview_EdgeJournals.ListViewItemSorter = lvwColumnSorter;
        }

        /// <summary>
        /// subscribe to USB events to detect the edge when it's inserted
        /// more info here: http://stackoverflow.com/questions/271238/how-do-i-detect-when-a-removable-disk-is-inserted-using-c 
        /// </summary>
        private void USBeventsubscription()
        {
            ManagementEventWatcher mgt_eventwatcher;
            ManagementScope mgtscope = new ManagementScope("root\\CIMV2");
            mgtscope.Options.EnablePrivileges = true;
            TimeSpan interval = new TimeSpan(0, 0, 10);

            // USB removed
            WqlEventQuery wql_usbremoved = new WqlEventQuery();
            wql_usbremoved.EventClassName = "__InstanceDeletionEvent";
            wql_usbremoved.WithinInterval = interval;
            wql_usbremoved.Condition = "TargetInstance ISA 'Win32_USBControllerdevice'";
            mgt_eventwatcher = new ManagementEventWatcher(mgtscope, wql_usbremoved);
            mgt_eventwatcher.EventArrived += new EventArrivedEventHandler(w_USBEvent);
            mgt_eventwatcher.Start();

            // USB inserted
            WqlEventQuery wql_usbinserted = new WqlEventQuery();
            wql_usbinserted.EventClassName = "__InstanceCreationEvent";
            wql_usbinserted.WithinInterval = interval;
            wql_usbinserted.Condition = "TargetInstance ISA 'Win32_USBControllerdevice'";
            mgt_eventwatcher = new ManagementEventWatcher(mgtscope, wql_usbinserted);
            mgt_eventwatcher.EventArrived += new EventArrivedEventHandler(w_USBEvent);
            mgt_eventwatcher.Start();
        }

        void w_USBEvent(object sender, EventArrivedEventArgs e)
        {
            checkEdgeFiles();
        }

        /// <summary>
        /// identify the onenote application when the tool starts and load the hierarchy of pages
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ESJImporterForm_Load(object sender, EventArgs e)
        {
            //bt_serializemin.Enabled = false;
            onenoteApp = new Microsoft.Office.Interop.OneNote.Application();
            readConfig();
            OneNoteFunctions.readONHierarchy(tree_OneNoteHierarchy);
            list_DirectoryWatchers = new ArrayList();
            checkEdgeFiles();

            dlg_preferences = new ImporterPreferences(pref_Settings);

            USBeventsubscription();
            listview_ChangeSort(0);

            log("[" + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + "]");
            /**/
        }

        private void ESJImporterForm_FormClosing(object sender, FormClosingEventArgs e)
        {
//            mgt_eventwatcher.Stop();      // destroyed by garbage collector => not good
            writeConfig();
        }

        #region preferences file
        /// <summary>
        /// read the static settings from the config file
        /// </summary>
        private void readConfig()
        {
            // list of watched folders
            if (!File.Exists(conffile))
            {
                pref_Settings.watchedfolders.Add(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
                return;
            }

            XmlSerializer xmlser = new XmlSerializer(typeof(Preferences));
            TextReader tr = new StreamReader(conffile);
            pref_Settings = (Preferences)xmlser.Deserialize(tr);
            tr.Close(); 
        }

        /// <summary>
        /// write the static settings to the config file
        /// </summary>
        private void writeConfig()
        {
            XmlSerializer xmlser = new XmlSerializer(typeof(Preferences));
            TextWriter tw = new StreamWriter(conffile);
            xmlser.Serialize(tw, pref_Settings);
            tw.Close(); 
            /*
            TextWriter tw = new StreamWriter(conffile);
            foreach (string addfolder in array_WatchedFolders)
            {
                tw.WriteLine(addfolder);
            }
            tw.Close();
             */
        }
        #endregion

        private string getNotebookID(TreeNode pageNode)
        {
            if (pageNode.Parent==null) return pageNode.Name;
            return getNotebookID(pageNode.Parent);
        }
        
        /// <summary>
        /// iterate through all pages and recreate note book structure in onenote
        /// requires that a notebook is selected
        /// DIFFERENT RECREATION STRATEGIES CURRENTLY
        /// 1) destination is a notebook: tabs become sections, with according pages part of it [DONE]
        /// 2) destination is a section: tabs become main pages (should pages become subpages? currently just naming of tabs) [DONE]
        /// 3) destination is a page: all sections on one page, tabs become headers
        /// </summary>
        /// <param name="esjnodes"></param>
        private void syncfullnotebook(ESJournal journal, string onenoteid)
        {
            string interpretedtext = "";

            /// note: subpages with attribute  _isSubPage="true"_  in _one:Page_ node
            /// TODO: create notebook if desired
            OneNoteFunctions.OneNoteTypes destinationtype = OneNoteFunctions.GetType(onenoteid);    // the type decides the behaviour
            log("destination type: " + destinationtype.ToString());

            // adjust progress bar
            dlg_progress.progbar_SyncingProgressNotebook.Minimum = 0;
            dlg_progress.progbar_SyncingProgressNotebook.Maximum = journal.edgejournalpages.Count;
            dlg_progress.progbar_SyncingProgressNotebook.Value = 0;
            dlg_progress.progbar_SyncingProgressNotebook.Step = 1;
            
            // iterate through all pages
            string destinationTabID = "";
            string sectionName = "Cover";
            int originalPageYOffset = pref_Settings.yOffset;
            int pcount = 0;

            if ((destinationtype == OneNoteFunctions.OneNoteTypes.Page) || (destinationtype == OneNoteFunctions.OneNoteTypes.SubPage))
            {
                // if sync destination is just a page, clear all content 
                log("clearing page " + onenoteid);
                OneNoteFunctions.ClearPage(onenoteid);
            }

            for (int n = 0; n < journal.edgejournalpages.Count; n++)
            {
                ESJournalPage curpage = (ESJournalPage)journal.edgejournalpages[n];
                bool newtab = false;
                string strPageID = "";
                
                if ((n == 0) || (curpage.tabname != ""))
                {
                    pcount = 0;
                    // new tab or beginning of document: create new section
                    sectionName = curpage.tabname;
                    interpretedtext += "<span style='font-weight:bold;text-decoration:underline'>"+sectionName + "</span><br>";
                    if (sectionName == "") sectionName = "Cover";

                    // create section (delete if existent)
                    // todo: handle more carefully (i.e. do not delete all pages and similar)

                    if ((destinationtype == OneNoteFunctions.OneNoteTypes.Notebook) || (destinationtype == OneNoteFunctions.OneNoteTypes.SectionGroup))
                        destinationTabID = OneNoteFunctions.CreateSection(onenoteid, sectionName, true);
                    else if (destinationtype == OneNoteFunctions.OneNoteTypes.Section)
                    {
                        destinationTabID = onenoteid;
                        strPageID = OneNoteFunctions.CreatePage(onenoteid, sectionName + "_" + pcount.ToString(), true);
                        if (strPageID == "") return;
                    }
                    if ((destinationtype == OneNoteFunctions.OneNoteTypes.Page) || (destinationtype == OneNoteFunctions.OneNoteTypes.SubPage))
                    {
                        if ((n > 0) || (curpage.tabname != ""))
                        {
                            Font headerfont = new Font("Times New Roman", 18, FontStyle.Bold | FontStyle.Underline);
                            OneNoteFunctions.AddText(onenoteid, 0, (double)pref_Settings.yOffset, sectionName, headerfont);
                            pref_Settings.yOffset += 20;
                        }
                    }
                    newtab = true;
                }
                
                // create new page for content
                // todo: update existing pages AS AN OPTION

                // get existing page:
                //string pageID = tree_OneNoteHierarchy.SelectedNode.Name;
                //string XMLPageContent;
                //onenoteApp.GetPageContent(pageID, out XMLPageContent, Microsoft.Office.Interop.OneNote.PageInfo.piAll);
                //XElement xpage = XElement.Parse(XMLPageContent);

                if ((destinationtype == OneNoteFunctions.OneNoteTypes.Notebook) || (destinationtype == OneNoteFunctions.OneNoteTypes.SectionGroup))
                    strPageID = OneNoteFunctions.CreatePage(destinationTabID, sectionName + "_" + pcount.ToString(), true);
                else if (destinationtype == OneNoteFunctions.OneNoteTypes.Section)
                {
                    if (!newtab)
                        strPageID = OneNoteFunctions.CreatePage(destinationTabID, sectionName + "_" + pcount.ToString(), true);
                }
                else if ((destinationtype == OneNoteFunctions.OneNoteTypes.Page) || (destinationtype == OneNoteFunctions.OneNoteTypes.SubPage))
                {
                    strPageID = onenoteid;
                }
                log("syncing page " + strPageID);

                // failure if no page was found / created
                if (strPageID == "")
                {
                    MessageBox.Show("page failure");
                    return;
                }

                /// 2) build the stroke collection from the specific page
                StrokeCollection esjstrokes = EdgeJournalFunctions.createStrokeCollectionFromPage(curpage, pref_Settings);

                // FURTHER LINKS FOR INK ANALYSIS:
                // http://msdn.microsoft.com/en-us/library/system.windows.ink.contextnode(v=vs.90).aspx
                // CREATECUSTOMRECOGNIZER!? http://msdn.microsoft.com/zh-cn/library/system.windows.ink.inkanalyzer.createcustomrecognizer(v=vs.85).aspx
                // ... http://msdn.microsoft.com/de-de/library/system.windows.ink.inkanalyzer.createcustomrecognizer(v=vs.85).aspx
                // optional: do interpretation here
//                InkAnalyzer IA_strokeinterpreter = new InkAnalyzer();
//                IA_strokeinterpreter.AddStrokes( esjstrokes );
                // TODO: languageid = CultureInfo.GetCultureInfo(
                // GetSystemDefaultLangID 
                // languages: http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(v=vs.71).aspx
                //IA_strokeinterpreter.AnalysisModes = AnalysisModes.PersonalizationEnabled???
                // cf http://www.einsteintech.net/apps/DisplayApp.aspx?path=publish&app=IAExplorer
                // and HELP on InkAnalyzer => create personal handwriting????
//                IA_strokeinterpreter.Analyze();
//                interpretedtext += IA_strokeinterpreter.GetRecognizedString() + "<br>-----------<br>";

                /// 3) build XML from the page node
                XElement serialisedDocument = OneNoteFunctions.buildOneNoteXML(strPageID, esjstrokes, pref_Settings);
                log("serialised page: ");
                log(serialisedDocument.ToString());

                // 4) update onenote and add content
                try
                {
                    onenoteApp.UpdatePageContent(serialisedDocument.ToString(), DateTime.MinValue);
                }
                catch (Exception ex)
                {
                    log("OneNote update caused an execption:");
                    log(ex.Message);
                    log("leaving...");
                    throw new Exception("EdgeSync cause an XML exception in OneNote" + System.Environment.NewLine + serialisedDocument.ToString());
                }
                log("OneNote updated successfully with page");
                log("");
                // todo: function to add page with content and name
                // capabilities: overwrite / add / interpret 

                if (destinationtype == OneNoteFunctions.OneNoteTypes.Section)
                {
                    if (!newtab)
                        OneNoteFunctions.MakePageSub(serialisedDocument);
                }
                if ((destinationtype == OneNoteFunctions.OneNoteTypes.Page) || (destinationtype == OneNoteFunctions.OneNoteTypes.SubPage))
                {
                    pref_Settings.yOffset += (int)(esjstrokes.GetBounds().Height * pref_Settings.ZoomFactor) + 20;
                }                

                pcount++;
                dlg_progress.progbar_SyncingProgressNotebook.PerformStep();
            }

            //MessageBox.Show(interpretedtext);
            //OneNoteFunctions.AddText(onenoteid, 500, 0, interpretedtext, SystemFonts.DefaultFont);

            // reset y offset
            pref_Settings.yOffset = originalPageYOffset;
        }

        /// <summary>
        /// synchronize just the selected partnership, not all 
        /// NOTE: this synchronises according to the predefined partnership of the edgefile selection, 
        /// not according to the selection in general (i.e. the onenote selection is ignored)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void syncnowtoolStripMenuItem_Click(object sender, EventArgs e)
        {
            PartnerShip curps = findPartnershipFromEdgeFile(listview_EdgeJournals.SelectedItems[0].Name);

            dlg_progress = new SyncProgress();
            dlg_progress.progbar_SyncingProgressTotal.Minimum = 0;
            dlg_progress.progbar_SyncingProgressTotal.Maximum = 1;
            dlg_progress.progbar_SyncingProgressTotal.Value = 0;
            dlg_progress.progbar_SyncingProgressTotal.Step = 1;
            dlg_progress.Show(this);

            syncPartnerShip(curps, ref dlg_progress);

            dlg_progress.Close();

            OneNoteFunctions.readONHierarchy(tree_OneNoteHierarchy);    // update onenote view
        }

        private void syncPartnerShip(PartnerShip ps, ref SyncProgress dlg_progress)
        {
            FileInfo ficurps = new FileInfo(ps.str_ESJFile);
            // only sync when file exists and is not uptodate
            if ((ficurps.Exists) && (ps.date_LastSync < ficurps.LastWriteTime))
            {
                dlg_progress.label_ProcessingFileName.Text = ps.str_ESJName + " (" + ps.str_ESJFile + ")";
                log(DateTime.Now.ToShortTimeString()+ " syncing "+ dlg_progress.label_ProcessingFileName.Text + " with "+ps.str_ONEID);

                // sync journal
                //
                dlg_progress.progbar_SyncingProgressNotebook.Value = 0;
                // get according journal
                EdgeJournal = new ESJournal(ps.str_ESJFile);
                // get notebook id
                string notebookid = ps.str_ONEID;
                // recreate the full notebook structure from ESJ in OneNote
                syncfullnotebook(EdgeJournal, notebookid);
                log("synchronisation completed...");
                log("");

                ps.date_LastSync = DateTime.Now;
                checkEdgeFiles();
            }

            dlg_progress.progbar_SyncingProgressNotebook.PerformStep();
        }

        /**/
        /// <summary>
        /// read the (full) content of a page and display
        /// when selected
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tree_OneNoteHierarchy_AfterSelect(object sender, TreeViewEventArgs e)
        {
            bt_CreatePartnership.ImageKey = "Link";

            // check whether partnership can be created
            bt_CreatePartnership.Enabled = false;
            if ((tree_OneNoteHierarchy.SelectedNode != null) && (listview_EdgeJournals.SelectedItems.Count > 0))
                if (listview_EdgeJournals.SelectedItems[0].ImageKey != "unknown")
                {
                    bt_CreatePartnership.Enabled = true;
                    // if both parts selected, allow destruction of partnership
                    PartnerShip curps = findPartnershipFromOneNoteID(tree_OneNoteHierarchy.SelectedNode.Name);
                    if ((curps != null) && (listview_EdgeJournals.SelectedItems[0].Name == curps.str_ESJFile))
                        bt_CreatePartnership.ImageKey = "Unlink";
                }

            // update paired view
            listview_EdgeJournals.Invalidate();
        }

        /// <summary>
        /// update the hierarchy of onenote pages
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bt_UpdateONHierarchy_Click(object sender, EventArgs e)
        {
            OneNoteFunctions.readONHierarchy(tree_OneNoteHierarchy);
        }


        #region helperfunctions
        /// <summary>
        /// check whether a treenodecollection contains a specific node AT ANY LEVEL
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="searchnode"></param>
        /// <returns></returns>
        private bool treeContainsNode(TreeNodeCollection tree, TreeNode searchnode)
        {
            if (tree.Contains(searchnode)) return true;
            foreach (TreeNode tn in tree)
            {
                if (tn.Nodes.Count > 0)
                    if (treeContainsNode(tn.Nodes, searchnode)) return true;
            }
            return false;
        }

        /// <summary>
        /// helper: count all checked nodes in a treeview
        /// </summary>
        /// <param name="tv"></param>
        /// <returns></returns>
        private int countCheckedNodes(TreeView tv)
        {
            int counter = 0;
            foreach (TreeNode tnhigh in tv.Nodes)
            {
                if (tnhigh.Checked == true) counter++;
            }
            return counter;
        }

        /// <summary>
        /// read the default folders and list all files
        /// check for an ".edge" folder and assume that this represents the Edge system
        /// </summary>
        public void checkEdgeFiles()
        {
            listview_EdgeJournals.ShowGroups = pref_Settings.showFolderNames;
            listview_EdgeJournals.Items.Clear();

            // check for the edge
            //EdgeAvailable = false;
            foreach (DriveInfo drive in DriveInfo.GetDrives())
            {
                string edgedir = drive.RootDirectory.ToString() + ".edge\\.esi-content\\";
                if (Directory.Exists(edgedir))
                {
                    if (!pref_Settings.watchedfolders.Contains(edgedir))
                    {   // if the folder is not on the watchlist, add it
                        bool found = false;
                        string oldfolder = "";
                        foreach (string folderpath in pref_Settings.watchedfolders)
                        {
                            string purewatchedfolder = folderpath.Substring(2).ToLower();
                            string pureedgefolder = edgedir.Substring(2).ToLower();
                            if (purewatchedfolder.Contains(pureedgefolder))
                            {
                                found = true;
                                oldfolder = folderpath;
                                break;
                            }
                        }
                        if (found)
                        {   // the folder is there but with a different driveletter => adjust
                            pref_Settings.watchedfolders.Remove(oldfolder);
                        }
                        // add the folder to the watch list
                        pref_Settings.watchedfolders.Add(edgedir);
                        //EdgeAvailable = true;
                    }
                }
            }

            // todo: start folder watchers to check for changes during execution
            // related link: http://www.codeproject.com/KB/cs/FileDirChangeNotifier.aspx
            // http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx
            // problem: make sure that not multiple watchers are initiated; clear all watchers in time! => how?
            listview_EdgeJournals.Groups.Clear();
            foreach (string folderpath in pref_Settings.watchedfolders)
            {
                ListViewGroup lvg = listview_EdgeJournals.Groups.Add(folderpath, folderpath);
                if (folderpath.Contains(".edge\\.esi-content\\"))
                    lvg.Header = "eDGe";

                DirectoryInfo DIfolder = new DirectoryInfo(folderpath);
                if (DIfolder.Exists)
                {
                    // TODO: include subfolders if so desired
                    //DirectoryInfo[] subfolders = dir.GetDirectories();
                    // recurse
                    string foldername = folderpath.Substring(folderpath.LastIndexOf("\\") + 1);
                    if (foldername == "") { foldername = folderpath; }

                    // outdated: show folder as node
                    // TreeNode tn_curfolder = tree_typicalsources.Nodes.Add(folderpath, foldername);

                    FileInfo[] files = DIfolder.GetFiles("*.esj");  // todo: add here other formats if required
                    foreach (FileInfo FIfile in files)
                    {
                        //tn_curfolder.Nodes.Add(FIfile.FullName, FIfile.Name);
                        string itemname = FIfile.Name;
                        string itemimage = "unlinked";

                        PartnerShip curps = findPartnershipFromEdgeFile(FIfile.FullName);
                        if (curps != null)
                        {
                            itemname = curps.str_ESJName;
                            if (FIfile.LastWriteTime > curps.date_LastSync)
                                itemimage = "modified";
                            else
                                itemimage = "uptodate";
                        }

                        ListViewItem lvi = listview_EdgeJournals.Items.Add(FIfile.FullName, itemname, itemimage);
                        //lvi.SubItems.Add(FIfile.LastWriteTime.ToString("dd/MM/yyyy HH:mm"); // .ToShortDateString()+ " "+FIfile.LastWriteTime.ToShortTimeString());
                        lvi.SubItems.Add(FIfile.LastWriteTime.ToShortDateString()+ " "+FIfile.LastWriteTime.ToShortTimeString());
                        lvi.SubItems.Add(((FIfile.Length / 1024.0)).ToString("#,#### kB"));
                        lvi.Group = lvg;
                        lvi.ForeColor = Color.Black;
                    }
                }
            }

            // show partnered files that are currently not available (not connected(
            if (pref_Settings.showUnavailablePartherships)
            {
                ArrayList array_listviewgroups = new ArrayList();
                foreach (ListViewGroup lvg in listview_EdgeJournals.Groups)
                {
                    array_listviewgroups.Add(lvg.Name);
                }
                array_listviewgroups.Sort();

                foreach (PartnerShip ps in pref_Settings.partnerships)
                {
                    if (!listview_EdgeJournals.Items.ContainsKey(ps.str_ESJFile))
                    {
                        ListViewItem lvi = listview_EdgeJournals.Items.Add(ps.str_ESJFile, ps.str_ESJName, "unknown");
                        lvi.SubItems.Add("");
                        lvi.SubItems.Add("");
                        lvi.ForeColor = Color.Gray;

                        // TODO: how to identify the right group? 
                        // this is a workaround and leads to errors if subfolders are in the watched folder list (e.g. "c:\" and "c:\system" => always belongs to "c:")
                        // yet another workaround: sort listviewgroups by size (ascending)
                        foreach (string lvgroupname in array_listviewgroups)
                        {
                            if (ps.str_ESJFile.IndexOf(lvgroupname) == 0)
                            {
                                lvi.Group = listview_EdgeJournals.Groups[lvgroupname];
                            }
                        }
                    }
                }
            }

        }
        #endregion


        /// <summary>
        /// refresh the file folder view
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void refreshToolStripMenuItem_Click(object sender, EventArgs e)
        {
            checkEdgeFiles();
        }

        /// <summary>
        /// open the preferences menu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bt_preferences_Click(object sender, EventArgs e)
        {
            //bool tmp = pref_Settings.showUnavailablePartherships;
            dlg_preferences.ShowDialog();

            // update display accordingly
            OneNoteFunctions.readONHierarchy(tree_OneNoteHierarchy);
            checkEdgeFiles();
        }

        /// <summary>
        /// display selected list view item
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listview_EdgeJournals_SelectedIndexChanged(object sender, EventArgs e)
        {
            bt_CreatePartnership.ImageKey = "Link";
            if (listview_EdgeJournals.SelectedItems.Count == 0)
            {
                bt_CreatePartnership.Enabled = false;
                return;
            }

            ListViewItem lvi = listview_EdgeJournals.SelectedItems[0];

            // check whether partnership can be created
            if (lvi.ImageKey == "unknown")
            {
                bt_CreatePartnership.Enabled = false;
            }
            else
                if (tree_OneNoteHierarchy.SelectedNode != null)
                    bt_CreatePartnership.Enabled = true;

            PartnerShip curps = findPartnershipFromEdgeFile(lvi.Name);
            if (curps != null)
            {
                // check for onenote counterpart
                TreeNode[] tnresult = tree_OneNoteHierarchy.Nodes.Find(curps.str_ONEID, true);
                if (tnresult.Count() == 0)
                {
                    if (MessageBox.Show("the paired onenote section seems to have been deleted - the partnership will be revoked", "Attention", MessageBoxButtons.OKCancel) == DialogResult.OK)
                    {
                        pref_Settings.partnerships.Remove(curps);
                        checkEdgeFiles();
                        tree_OneNoteHierarchy.Invalidate();
                        return;
                    }
                }
                // if both parts selected, allow destruction of partnership
                if (tree_OneNoteHierarchy.SelectedNode != null)
                    if (tree_OneNoteHierarchy.SelectedNode.Name == curps.str_ONEID)
                        bt_CreatePartnership.ImageKey = "Unlink";
            }
            tree_OneNoteHierarchy.Invalidate();
        }

        /// <summary>
        /// execute synchronisation
/// todo: define direction etc., details in partnership
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bt_Sync_Click(object sender, EventArgs e)
        {
            dlg_progress = new SyncProgress();
            // start syncing
            dlg_progress.label_ProcessingFileName.Text = "";
            dlg_progress.progbar_SyncingProgressTotal.Minimum = 0;
            dlg_progress.progbar_SyncingProgressTotal.Maximum = pref_Settings.partnerships.Count;
            dlg_progress.progbar_SyncingProgressTotal.Value = 0;
            dlg_progress.progbar_SyncingProgressTotal.Step = 1;
            dlg_progress.Show(this);

            foreach (PartnerShip curps in pref_Settings.partnerships)
            {
                syncPartnerShip(curps, ref dlg_progress);
            }
            dlg_progress.Close();

            OneNoteFunctions.readONHierarchy(tree_OneNoteHierarchy);    // update onenote view
        }

        /// <summary>
        /// double click a journal => display it
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listview_EdgeJournals_DoubleClick(object sender, EventArgs e)
        {
            if (listview_EdgeJournals.SelectedItems.Count == 0) return;
            EdgeJournalDisplay dlg_JournalDisplay = new EdgeJournalDisplay(listview_EdgeJournals.SelectedItems[0].Name, pref_Settings);
            dlg_JournalDisplay.Text = "Displaying " + listview_EdgeJournals.SelectedItems[0].Name;
            dlg_JournalDisplay.ShowDialog();
        }

        /// <summary>
        /// display the XML content of the selected OneNote entry
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void showXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (tree_OneNoteHierarchy.SelectedNode == null) return;

            //var onenoteApp = new OneNote.Application();
            string notebookXml;
            onenoteApp.GetHierarchy(null, OneNote.HierarchyScope.hsPages, out notebookXml);

            var doc = XDocument.Parse(notebookXml);
            var ns = doc.Root.Name.Namespace;

            string pageID = tree_OneNoteHierarchy.SelectedNode.Name;

            string XMLPageContent;
            onenoteApp.GetPageContent(pageID, out XMLPageContent, Microsoft.Office.Interop.OneNote.PageInfo.piBasic); // piAll
            XElement xpagebase = XElement.Parse(XMLPageContent);
            onenoteApp.GetPageContent(pageID, out XMLPageContent, Microsoft.Office.Interop.OneNote.PageInfo.piAll);
            XElement xpageext = XElement.Parse(XMLPageContent);

            //string BINPageContent;
            //onenoteApp.GetBinaryPageContent(pageID, "{5F66E677-8E99-46DD-B65F-AFAADAF9B651}{18}{B0}", out BINPageContent);

            OneNoteDisplay dlg_OneNote = new OneNoteDisplay();
            dlg_OneNote.basicOneNoteData = xpagebase;
            dlg_OneNote.extendedOneNoteData = xpageext;
            //dlg_OneNote.tb_OneNoteXMLView.Text = xpage.ToString();
            dlg_OneNote.ShowDialog();
        }

        // todo: go to page?
        /// <summary>
        /// open onenote on the selected section
        /// note that due to restrictions of onenote, I cannot jump to pages or empty notebooks
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void goToOneNoteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode ONselectedsection = tree_OneNoteHierarchy.SelectedNode;
            string onenoteentryid = ONselectedsection.Name;
            // go to entry
            onenoteApp.NavigateTo(onenoteentryid, null, false);

            // bring to front
            System.Diagnostics.Process[] onenoteprocs = System.Diagnostics.Process.GetProcessesByName("ONENOTE");
            if (onenoteprocs != null)
            {
                IntPtr hwnd = onenoteprocs[0].MainWindowHandle;
                SetForegroundWindow(hwnd);
            }

        }

        /// <summary>
        /// the context menu does not by default select the node under the cursor
        /// => ensure that the right node is selected
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ctx_onenote_Opening(object sender, CancelEventArgs e)
        {
            TreeNode tnselect = tree_OneNoteHierarchy.GetNodeAt(tree_OneNoteHierarchy.PointToClient(Control.MousePosition));
            if (tnselect != null)
            {
                tree_OneNoteHierarchy.SelectedNode = tnselect;
                ctx_onenote.Items["goToOneNoteToolStripMenuItem"].Enabled = true;
                ctx_onenote.Items["showXMLToolStripMenuItem"].Enabled = true;
            }
            else
            {
                ctx_onenote.Items["goToOneNoteToolStripMenuItem"].Enabled = false;
                ctx_onenote.Items["showXMLToolStripMenuItem"].Enabled = false;
            }
        }

        private void ctx_files_Opening(object sender, CancelEventArgs e)
        {
            //Point mousept = tree_OneNoteHierarchy.PointToClient(Control.MousePosition);
            //ListViewItem lviselect = listview_EdgeJournals.GetItemAt(mousept.X,mousept.Y);
            if (listview_EdgeJournals.SelectedItems.Count > 0)
            {
                ctx_files.Items["showContentToolStripMenuItem"].Enabled = true;
                ctx_files.Items["renameToolStripMenuItem"].Enabled = true;
                ctx_files.Items["syncnowtoolStripMenuItem"].Enabled = true;

                PartnerShip curps = findPartnershipFromEdgeFile(listview_EdgeJournals.SelectedItems[0].Name);
                if (curps == null)
                {
                    ctx_files.Items["renameToolStripMenuItem"].Enabled = false;
                    ctx_files.Items["syncnowtoolStripMenuItem"].Enabled = false;
                }
            }
            else
            {
                ctx_files.Items["showContentToolStripMenuItem"].Enabled = false;
                ctx_files.Items["renameToolStripMenuItem"].Enabled = false;
                ctx_files.Items["syncnowtoolStripMenuItem"].Enabled = false;
            }
        }

        /// <summary>
        /// rename an existing edge journal file 
        /// only works for registered partnerships (other files are unknown)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void renameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            listview_EdgeJournals.LabelEdit = true;
            listview_EdgeJournals.SelectedItems[0].BeginEdit();
        }
        private void listview_EdgeJournals_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            listview_EdgeJournals.LabelEdit = false;
            // get partnership
            PartnerShip curps = findPartnershipFromEdgeFile(listview_EdgeJournals.SelectedItems[0].Name);
            curps.str_ESJName = e.Label;
        }

        /// <summary>
        /// create a partnership on basis of the current selection
        /// or destroy it, if already existent
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void createPartnershipToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string esjname = "";
            if (tree_OneNoteHierarchy.SelectedNode == null)
            {
                MessageBox.Show("You need to select a OneNote counterpart first");
                return;
            }
            if (tree_OneNoteHierarchy.SelectedImageKey == "unavailable")
            {
                MessageBox.Show("This file is not availabe");
            }
            PartnerShip curps = findPartnershipFromEdgeFile(listview_EdgeJournals.SelectedItems[0].Name);
            bool add = true;
            if (curps != null)
            {
                if (curps.str_ONEID != tree_OneNoteHierarchy.SelectedNode.Name)
                {   // existing partnership with different partners
                    if (MessageBox.Show("There already exists a partnership with the selected file - are you sure you want to replace it?", "Attention", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                        return;
                }
                else
                {   // existing partnership => delete?
                    if (MessageBox.Show("Are you sure you want to destroy this partnership?", "Attention", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                        return;
                    add = false;
                }
                pref_Settings.partnerships.Remove(curps);
            }

            // create partnership and register it
            if (add)
            {
                PartnerShip newpartnership = new PartnerShip(listview_EdgeJournals.SelectedItems[0].Name, tree_OneNoteHierarchy.SelectedNode.Name);
                if (esjname != "") newpartnership.str_ESJName = esjname;
                pref_Settings.partnerships.Add(newpartnership);
            }

            checkEdgeFiles();
            listview_EdgeJournals.Invalidate();
            tree_OneNoteHierarchy.Invalidate();
            bt_CreatePartnership.Enabled = false;
        }

        /// <summary>
        /// helper: find the partnership associated with an edge file
        /// </summary>
        /// <param name="edgefile"></param>
        /// <returns></returns>
        private PartnerShip findPartnershipFromEdgeFile(string edgefile)
        {
            foreach (PartnerShip test in pref_Settings.partnerships)
            {
                if (test.str_ESJFile == edgefile)
                    return test;
            }
            return null;
        }

        /// <summary>
        /// helper: find the partnership associated with an onenote id
        /// </summary>
        /// <param name="edgefile"></param>
        /// <returns></returns>
        private PartnerShip findPartnershipFromOneNoteID(string onenoteID)
        {
            foreach (PartnerShip test in pref_Settings.partnerships)
            {
                if (test.str_ONEID == onenoteID)
                    return test;
            }
            return null;
        }

        /// <summary>
        /// show the partnership overview dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bt_Partnerships_Click(object sender, EventArgs e)
        {
            Partnerships dlg_PartnerhsipDisplay = new Partnerships(ref pref_Settings.partnerships);
            dlg_PartnerhsipDisplay.ShowDialog();

        }

        
        // functions to ensure that the selection / the partnership is always visible
        #region ownerdrawn items
        private void listview_EdgeJournals_DrawItem(object sender, DrawListViewItemEventArgs e)
        {
            Color backcolor = listview_EdgeJournals.BackColor;
            Color forecolor = listview_EdgeJournals.ForeColor;
            if (e.Item.ImageKey == "unknown") forecolor = Color.Gray;

            e.Item.UseItemStyleForSubItems = true;

            if ((!e.Item.Selected) || (!listview_EdgeJournals.Focused))
            {   
                // TODO: if mouse is in onenote list, highlight partnership, if existent
                // also, if selected?
                if (tree_OneNoteHierarchy.SelectedNode != null)
                {
                    PartnerShip curonps = findPartnershipFromOneNoteID(tree_OneNoteHierarchy.SelectedNode.Name);
                    if (curonps != null)
                    {
                        ListViewItem[] lviresult = listview_EdgeJournals.Items.Find(curonps.str_ESJFile, false);
                        if (lviresult.Count() > 0)
                        {
                            if (lviresult[0] == e.Item)
                            {   // item belongs in a partnership
                                backcolor = Color.Yellow;
                            }
                        }
                    }
                }
            }

            if (e.Item.Selected)
            {
                float w = e.Graphics.MeasureString(e.Item.Text, tree_OneNoteHierarchy.Font).Width;
                if (listview_EdgeJournals.Focused)
                {   // item is selected and listview is focused
                    backcolor = Color.Red; // SystemColors.Highlight;
                    forecolor = Color.White;
                    // this is ignored => why?
                }
                else
                {   // item is selected and listview is not focused
                    backcolor = SystemColors.ActiveCaption;
                }
            }

            e.Item.BackColor = backcolor;
            e.Item.ForeColor = forecolor;
            e.DrawDefault = true;
        }

        private void listview_EdgeJournals_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            e.DrawDefault = true;
            /*
            //e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds);
            e.DrawBackground();
            e.DrawText();
            //e.Graphics.DrawString(e.Header.Text, e.Font, new SolidBrush(e.ForeColor), e.Bounds);
            if (lvwColumnSorter.SortColumn == e.ColumnIndex)
            {
                e.Graphics.DrawString("\u02C4", e.Font, new SolidBrush(e.ForeColor), e.Bounds.Right - 12, e.Bounds.Top);
            }*/
        }

        private void listview_EdgeJournals_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            listview_ChangeSort(e.Column);
        }

        private void listview_ChangeSort(int column)
        {
            string sort = "";
            // Determine if clicked column is already the column that is being sorted.
            if (column == lvwColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                if (lvwColumnSorter.Order == SortOrder.Ascending)
                {
                    lvwColumnSorter.Order = SortOrder.Descending;
                    sort = "\u02C5 ";
                }
                else
                {
                    lvwColumnSorter.Order = SortOrder.Ascending;
                    sort = "\u02C4 ";
                }
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                lvwColumnSorter.SortColumn = column;
                lvwColumnSorter.Order = SortOrder.Ascending;
                sort = "\u02C4 ";
            }

            // Perform the sort with these new sort options.
            listview_EdgeJournals.Sort();

            listview_EdgeJournals.Columns[0].Text = "Name";
            listview_EdgeJournals.Columns[1].Text = "Date Modified";
            listview_EdgeJournals.Columns[2].Text = "Size";
            listview_EdgeJournals.Columns[column].Text = sort + listview_EdgeJournals.Columns[column].Text;
        }


        private void tree_OneNoteHierarchy_DrawNode(object sender, DrawTreeNodeEventArgs e)
        {
            // THIS IS CHEATING: THERE IS A BUG HERE WHICH LEADS TO WRONG BOUNDARIES  !!!!
            // WHERE???
            if (e.Bounds.X < 0) return;

            if (tree_OneNoteHierarchy.SelectedNode != e.Node)
            {   // node is not selected
                if (listview_EdgeJournals.SelectedItems.Count > 0)
                {
                    // TODO: if mouse is in edge journals list, highlight partnership, if existent
                    // also, if selected? (but only when in focus)

                    PartnerShip curps = findPartnershipFromEdgeFile(listview_EdgeJournals.SelectedItems[0].Name);
                    if (curps != null)
                    {   // highlight partnered items
                        TreeNode[] tnresult = tree_OneNoteHierarchy.Nodes.Find(curps.str_ONEID, true);
                        if (tnresult.Count() > 0)
                        {
                            if (tnresult[0] == e.Node)
                            {
                                e.Graphics.FillRectangle(Brushes.Yellow, e.Bounds);
                                e.DrawDefault = false;
                                e.Graphics.DrawString(e.Node.Text, tree_OneNoteHierarchy.Font, Brushes.Black, e.Bounds.X, e.Bounds.Y);
                                //MessageBox.Show(e.Node.Text + " ( " + e.Bounds.X);
                                return;
                            }
                            else if (treeContainsNode(e.Node.Nodes, tnresult[0]))// (e.Node.Nodes.Contains(tnresult[0]))
                            {
                                e.Graphics.FillRectangle(Brushes.LightYellow, e.Bounds);
                                e.Graphics.DrawString(e.Node.Text, tree_OneNoteHierarchy.Font, Brushes.Black, e.Bounds.X, e.Bounds.Y);
                                return;
                            }
                        }
                    }
                }
            }
            else
            {
                float w = e.Graphics.MeasureString(e.Node.Text, tree_OneNoteHierarchy.Font).Width;
                if (tree_OneNoteHierarchy.Focused)
                {
                    e.Graphics.FillRectangle(new SolidBrush(SystemColors.Highlight), e.Bounds.X, e.Bounds.Y, w, e.Bounds.Height);
                    e.Graphics.DrawString(e.Node.Text, tree_OneNoteHierarchy.Font, Brushes.White, e.Bounds.X, e.Bounds.Y);
                    return;
                }
                else
                {
                    e.Graphics.FillRectangle(new SolidBrush(SystemColors.ActiveCaption), e.Bounds.X, e.Bounds.Y, w, e.Bounds.Height);
                    e.Graphics.DrawString(e.Node.Text, tree_OneNoteHierarchy.Font, Brushes.Black, e.Bounds.X, e.Bounds.Y);
                    return;
                }
            }

            e.DrawDefault = true;
        }

        private void listview_EdgeJournals_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            Point mousept = listview_EdgeJournals.PointToClient(Control.MousePosition);
            ListViewItem lviselect = listview_EdgeJournals.GetItemAt(32,mousept.Y);
            if (lviselect != null)
                lviselect.Selected = true;
        }
        #endregion

        /// <summary>
        /// change tool tip so as to display information about the Edge Journal files
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listview_EdgeJournals_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            Point mousept = listview_EdgeJournals.PointToClient(Control.MousePosition);
            ListViewItem lviselect = listview_EdgeJournals.GetItemAt(mousept.X, mousept.Y);
            if (lviselect == null)
            {
                //tooltip_Files.Hide(listview_EdgeJournals);
                tooltip_Files.RemoveAll();
                return;
            }
            if (mousept.X > 32)
            {
                if (tooltip_Files.GetToolTip(listview_EdgeJournals) != lviselect.Name)
                    tooltip_Files.SetToolTip(listview_EdgeJournals, lviselect.Name);
            }
            else
            {
                string txt = "TODO: Status, last modified, last synced";
                PartnerShip curps = findPartnershipFromEdgeFile(lviselect.Name);
                switch (lviselect.ImageKey)
                {
                    case "unknown":
                        txt = "This file is currently not available";
                        break;
                    case "uptodate":
                        txt = "This file is uptodate - last sync: " + curps.date_LastSync.ToShortDateString();
                        break;
                    case "modified":
                        FileInfo curfi = new FileInfo(lviselect.Name);
                        txt = "The synchronisation is out of date - last edit: " + curfi.LastWriteTime.ToShortDateString() + "; last sync: " + curps.date_LastSync.ToShortDateString();
                        break;
                    case "unlinked":
                        txt = "This files is not subject to synchronisation";
                        break;
                    default:
                        txt = "";
                        break;
                }
                if (tooltip_Files.GetToolTip(listview_EdgeJournals) != txt)
                    tooltip_Files.SetToolTip(listview_EdgeJournals, txt);
            }
        }

        /// <summary>
        /// "ABOUT" button clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bt_About_Click(object sender, EventArgs e)
        {
            About dlgabout = new About();
            dlgabout.Show(this);
        }

        /// <summary>
        /// HELP button clicked => go to website
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bt_Help_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://edgesync.codeplex.com/documentation");
        }

        private void log(string message)
        {
            if (logfile != "")
            {
                using (StreamWriter sw = File.AppendText(logfile))
                {
                    sw.WriteLine(message);
                    sw.Close();
                }
            }
        }

    }


    /// <summary>
    /// the class structure for defining a single partnership between ESJ and OneNote
    /// </summary>
    public class PartnerShip
    {
        public string str_ESJFile;      // full path & name of the ESJfile
        public string str_ESJName;      // assigned name for the journal file
        public string str_ONEID;      // full path of the OneNote notebook
        public DateTime date_LastSync;  // data & time of last synchronisation

        // additional settings will go here
        // todo: select sections / pages rather than full notebooks
        // todo: "read and convert text automatically"-option

        public PartnerShip()
        {
            str_ESJFile = "";
            str_ESJName = "";
            str_ONEID = "";
        }

        public PartnerShip(string edgefile, string onenoteID)
        {
            str_ESJFile = edgefile;
            string strtmp = edgefile.Substring(edgefile.LastIndexOf("\\")+1);
            strtmp = strtmp.Substring(0, strtmp.Length - 4);
            str_ESJName = strtmp; 
            str_ONEID = onenoteID;
            //date_LastSync = new DateTime();
        }

        public void UpdateSync()
        {
            date_LastSync = DateTime.Now;
        }
    }

    /// <summary>
    /// all preferences settings
    /// includes: watched folders
    /// conversion settings
    /// </summary>
    [XmlInclude(typeof(PartnerShip))]
    public class Preferences
    {   // todo: gets & sets
        public ArrayList watchedfolders;
        public ArrayList partnerships;
        public enum widths { Fine=0, Medium, Thick };
        public enum colours { Black=0, Red, Blue, Yellow, White };
        //public enum devices { Edge = 0, PocketEdge }; 
        public float[] StrokeWidth;
        public string DeviceType;
        public double ZoomFactor;
        public int xOffset;
        public int yOffset;
        public bool showUnavailablePartherships;
        public bool showFolderNames;
        public bool convertHandwriting;
        [XmlIgnore]
        public Color[] StrokeColour;
        public XmlElement xmlStrokeColour
        {
            get
            {
                XmlDocument xcols = new XmlDocument();
                xcols.LoadXml("<xcols></xcols>");
                for (int i=0; i<StrokeColour.Count();i++)
                {
                    XmlElement xcol = xcols.CreateElement("colour");
                    xcol.InnerText=StrokeColour[i].ToArgb().ToString();
                    xcols.DocumentElement.AppendChild(xcol);
                }
                return xcols.DocumentElement;
            }
            set
            {
                StrokeColour = new Color[5];
                for (int i = 0; i < value.ChildNodes.Count;i++)
                {
                    StrokeColour[i] = Color.FromArgb(int.Parse(value.ChildNodes[i].InnerText));
                }
            }
        }

        private void init()
        {
            watchedfolders = new ArrayList();
            partnerships = new ArrayList();
            showUnavailablePartherships = true;
            showFolderNames = true;
            StrokeColour = new Color[5];
            resetColours();
            StrokeWidth = new float[3];
            resetWidths();
            resetZoom();
        }

        public Preferences()
        {
            init();
        }

        public void resetZoom()
        {
            ZoomFactor = 1.5;
            xOffset = -10;
            yOffset = 50;
        }

        public void resetColours()
        {
            setColours(Color.Black, Color.Red, Color.Blue, Color.Yellow, Color.LightGray);
        }

        public void setColours(Color black, Color red, Color blue, Color yellow, Color white)
        {
            StrokeColour[(int)colours.Black] = black;
            StrokeColour[(int)colours.Red] = red;
            StrokeColour[(int)colours.Blue] = blue;
            StrokeColour[(int)colours.Yellow] = yellow;
            StrokeColour[(int)colours.White] = white;
        }

        public Color getColor(string colorname)
        {
            Color col = Color.Black;
            switch (colorname.ToLower())
            {
                case "red":
                    col = StrokeColour[(int)Preferences.colours.Red];
                    break;
                case "blue":
                    col = StrokeColour[(int)Preferences.colours.Blue];
                    break;
                case "yellow":
                    col = StrokeColour[(int)Preferences.colours.Yellow];
                    break;
                case "white":
                    col = StrokeColour[(int)Preferences.colours.White];
                    break;
                default:
                    col = StrokeColour[(int)Preferences.colours.Black];
                    break;
            }
            return col;
        }

        public void resetWidths()
        {
            setWidths((float)0.85, (float)1.41, (float)2.26);
        }

        public void setWidths(float fine, float medium, float thick)
        {
            StrokeWidth[(int)widths.Fine] = fine;
            StrokeWidth[(int)widths.Medium] = medium;
            StrokeWidth[(int)widths.Thick] = thick;
        }

        public float getWidth(string strwidth)
        {
            float flwidth = (float) 0.85;
            switch (strwidth)
            {
                case "0.85":
                    // fine
                    flwidth = StrokeWidth[(int)Preferences.widths.Fine]; 
                    break;
                case "1.41":
                    // medium
                    flwidth = StrokeWidth[(int)Preferences.widths.Medium];
                    break;
                case "2.26":
                    // thick
                    flwidth = StrokeWidth[(int)Preferences.widths.Thick];
                    break;
            }
            return flwidth;

        }

        public void setDeviceType(string devtype)
        {
            DeviceType = devtype;
        }

        public string getDeviceType()
        {
            return DeviceType;
        }

        public void setHandwriting(bool active)
        {
            convertHandwriting = active;
        }

        public bool getHandwriting()
        {
            return convertHandwriting;
        }

    }

}

